<template>
	<el-form
		layout="inline"
		:class="['buildForm', hyFormConfig.type === 'view' ? 'no-style' : '']"
		ref="hyFormRef"
		:label-width="hyFormConfig.labelWidth || '120px'"
		:model="hyForm"
	>
		<template v-for="(item, key) of hyFormFields">
			<!-- 单选框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'radio')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-radio-group v-model="hyForm[key]" @change="(option:Event)  => {item.change ? item.change(option) : null;}">
						<el-radio v-for="option in item.options" :value="option.value" :label="option.label" :key="option">{{ option.label }}</el-radio>
					</el-radio-group>
				</el-form-item>
			</span>
			<!-- input输入框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'input')">
				<!-- 提示框，默认不展示 -->
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '输入')">
					<el-tooltip
						:disabled="!item.showTooltip ?? true"
						:effect="item.tooltipProps?.effect || 'dark'"
						:content="item.tooltipProps?.content || ''"
						:raw-content="item.tooltipProps?.rawContent || false"
						:placement="item.tooltipProps?.placement || 'top-start'"
					>
						<el-input
							:show-word-limit="item.showWordLimit || false"
							:show-password="item.showPassword || false"
							:disabled="setDisabled(item)"
							v-model.trim="hyForm[key]"
							:maxlength="item.maxlength || 200"
							:placeholder="setPlaceholder(item, '输入')"
							@focus="(e:Event) => setFocus(item, e)"
							@blur="(e:Event) => setBlur(item, e)"
							@click="(e:Event) => setClick(item, e)"
							:formatter="item.formatter?(value:string)=> item.formatter(value):null"
						>
							<template v-if="item.append && hyFormConfig.type !== 'view'" #append>
								<el-button @click="(e:Event) =>item.appendClick?item.appendClick(e):null" :icon="item.icon" />
							</template>
						</el-input>
					</el-tooltip>
				</el-form-item>
			</span>
			<!-- 数字输入框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'inputNumber')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '输入')">
					<el-input-number
						:placeholder="setPlaceholder(item, '输入')"
						class="flex1"
						:controls="false"
						:precision="item.precision"
						:step="item.step || 1"
						:max="item.max"
						:min="item.min"
						:disabled="setDisabled(item)"
						v-model.number="hyForm[key]"
						@focus="(e:Event)  => setFocus(item, e)"
						@blur="(e:Event) => setBlur(item, e)"
					/>
					<span
						v-if="item.append"
						style="
							background-color: #f5f7fa;
							color: #909399;
							display: inline-block;
							border: 1px solid #dcdfe6;
							border-radius: 4px;
							padding: 0 20px;
							height: 40px;
							line-height: 40px;
						"
					>
						{{ item.append }}
					</span>
				</el-form-item>
			</span>
			<!-- 金额输入框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'inputMoney')">
				<el-form-item
					:prop="key"
					:label="item.label"
					:label-width="setLabelWidth(item)"
					:rules="[
						{
							required: item.required,
							pattern: /^(\d{1,3}(,\d{3})*|\d+)(\.\d{1,2})?$/,
							message: '请输入正确的金额',
						},
					]"
				>
					<el-input
						:disabled="setDisabled(item)"
						v-model.trim="hyForm[key]"
						:maxlength="item.maxlength || 15"
						:placeholder="setPlaceholder(item, '输入')"
						@focus="(e:Event) => setFocus(item, e)"
						@click="(e:Event) => setClick(item, e)"
						:parser="(value:any) => value.replace(/\¥\s?|(,*)/g, '')"
						:formatter="(value:any) => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
					>
					</el-input>
				</el-form-item>
			</span>
			<!-- 下拉框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'select')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-tooltip
						:disabled="!item.showTooltip ?? true"
						:effect="item.tooltipProps?.effect || 'dark'"
						:content="item.tooltipProps?.content || ''"
						:raw-content="item.tooltipProps?.rawContent || false"
						:placement="item.tooltipProps?.placement || 'top-start'"
					>
						<el-select
							class="flex1"
							:mode="item.mode || 'default'"
							style="width: 100%"
							:multiple="item.multiple"
							:filterable="item.filterable || true"
							:clearable="item.clearable || true"
							:collapse-tags="item.collapseTags"
							:collapse-tags-tooltip="item.collapseTagsTooltip"
							:disabled="setDisabled(item)"
							v-model="hyForm[key]"
							:placeholder="setPlaceholder(item, '选择')"
							@change="
                    (option:Event)  => {
                      item.change ? item.change(option) : null;
                    }
                  "
						>
							<el-option
								v-for="option in item.options"
								:key="option.key || option.value"
								:label="option.label"
								:value="option.value"
								:disabled="option.disabled || false"
							/>
						</el-select>
					</el-tooltip>
					<span
						v-if="item.append"
						style="
							background-color: #f5f7fa;
							color: #909399;
							display: inline-block;
							border: 1px solid #dcdfe6;
							border-radius: 4px;
							padding: 0 20px;
							height: 40px;
							line-height: 40px;
						"
					>
						{{ item.append }}
					</span>
				</el-form-item>
			</span>
			<!-- 日期选择 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'date')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-date-picker
						:key="key"
						@focus="(e:Event) => setFocus(item, e)"
						@blur="(e:Event)  => setBlur(item, e)"
						@change="(e:Event)  => setChange(item, e)"
						:disabled="setDisabled(item)"
						v-model="hyForm[key]"
						:type="item.picker || 'date'"
						:format="item.showFormat || 'YYYY-MM-DD HH:mm:ss'"
						:placeholder="setPlaceholder(item, '选择')"
						:value-format="item.valueFormat || item.showFormat || 'YYYY-MM-DD HH:mm:ss'"
						style="width: 100%"
						start-placeholder="开始时间"
						end-placeholder="结束时间"
						:disabled-date="item.disabledDate || null"
						:picker-options="item.pickerOptions || ''"
						:shortcuts="item.shortcuts || []"
						:default-time="item.defaultTime"
					/>
				</el-form-item>
			</span>
			<!-- 多行输入框 -->
			<span class="item-single" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'textarea')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '输入')">
					<el-input
						type="textarea"
						show-word-limit
						:placeholder="setPlaceholder(item, '输入')"
						:disabled="setDisabled(item)"
						v-model="hyForm[key]"
						:rows="item.rows || 4"
						:maxlength="item.maxlength || 2000"
					/>
				</el-form-item>
			</span>
			<!-- 多选框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'checkBox')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-checkbox-group v-model="hyForm[key]" :disabled="item.disabled" :placeholder="setPlaceholder(item, '选择')">
						<el-checkbox v-for="option in item.options" :label="option.value" :key="option.value">{{ option.label }}</el-checkbox>
					</el-checkbox-group>
				</el-form-item>
			</span>
			<!-- 级联 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'cascader')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-cascader
						:placeholder="setPlaceholder(item, '选择')"
						:disabled="setDisabled(item)"
						v-model="hyForm[key]"
						:options="item.options || []"
						:props="item.props || {}"
						:show-all-levels="item.showAllLevels || false"
						:clearable="item.clearable || true"
						collapse-tags
						style="width: 100%"
						filterable
						@change="
									(option:Event)  => {
										item.change ? item.change(option) : null;
									}
								"
					/>
				</el-form-item>
			</span>
			<!-- 树选择框 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'tree-select')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '选择')">
					<el-tree-select
						:ref="key"
						:clearable="item.clearable || true"
						filterable
						:placeholder="setPlaceholder(item, '选择')"
						:disabled="setDisabled(item)"
						v-model="hyForm[key]"
						:data="item.options"
						:multiple="item.multiple || false"
						:render-after-expand="false"
						:setCheckedKeys="item.setCheckedKeys"
						:default-checked-keys="item.defaulCheckedKeys || []"
						:show-checkbox="item.showCheckbox ?? true"
						@remove-tag="(option:any)  => {
                      item.remove ? item.remove(option) : null;
                    }"
						@check="
                    (option:any,data?:any)  => {
                      item.check ? item.check(option,data) : null;
                    }
                  "
						@node-click=" (option:any,data?:any)  => {
                      item.nodeCheck ? item.nodeCheck(option,data) : null;
                    }"
						style="width: 100%"
					/>
				</el-form-item>
			</span>
			<!-- 上传 -->
			<span class="item-single" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'upload')">
				<el-form-item :prop="key" :label="item.label" :label-width="setLabelWidth(item)" :rules="setRule(item, '上传')">
					<HyUpload
						:fileType="item.fileType"
						:fileSize="item.fileSize"
						:type="hyFormConfig.type"
						v-model="hyForm[key]"
						:uploadFileUrl="item.uploadFileUrl"
					/>
				</el-form-item>
			</span>
			<!-- 下拉菜单 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'dropdown')">
				<el-dropdown>
					<el-button type="primary">
						{{ item.lable }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
					</el-button>
					<template #dropdown>
						<el-dropdown-menu>
							<el-dropdown-item
								v-for="option in item.options"
								:key="option.key || option.value"
								:value="option.value"
								@click="clickDropdown(option.value)"
								>{{ option.label }}</el-dropdown-item
							>
						</el-dropdown-menu>
					</template>
				</el-dropdown>
			</span>
			<!-- 按钮 -->
			<span class="item" v-show="!item.hidden" :key="`${key}_col`" v-if="setRemove(item, 'button')">
				<el-button @click="clickDropdown" type="primary">
					{{ item.lable }}
				</el-button>
			</span>
		</template>
		<!-- 插槽，自定义内容-->
		<slot name="custom"></slot>
	</el-form>
</template>

<script lang="ts" setup>
import { ref, watch, toRefs } from 'vue';
import HyUpload from '/@/components/HyUpload/index.vue';
import { ElMessage } from 'element-plus';

const props = defineProps({
	hyFormConfig: {
		type: Object,
		default: () => {
			return {
				labelWidth: '120px',
				type: 'submit',
				showErrorMessage: true,
			};
		},
	},
	hyFormFields: {
		default: () => {},
		type: Object,
	},
	hyFormDefault: {
		default: () => {},
		type: Object,
	},
});
const { hyFormFields, hyFormConfig } = toRefs(props);
interface Iitem {
	type: string;
	prop: string;
	max?: number;
	min?: number;
	label: string;
	rules?: any[];
	hidden?: boolean;
	picker?: string;
	showFormat?: string;
	valueFormat?: string;
	pickerOptions?: any;
	rows?: number;
	maxlength?: number;
	disabled?: boolean;
	placeholder?: string;
	options?: any[];
	required?: false;
	remove?: boolean;
	labelWidth?: string;
	multiple?: boolean;
	hiddenTooltip?: boolean;
	tooltipProps?: any;
	fileSize?: number;
	limit?: number;
	fileType?: string[];
	showWay?: string;
	focus?: (e: Event) => {};
	blur?: (e: Event) => {};
	change?: (e: Event) => {};
	click?: (e: Event) => {};
}

// 初始化表单
const hyForm = ref<any>({});
const init = (data: any) => {
	if (data && Object.keys(data).length > 0)
		Object.keys(data).forEach((key) => {
			hyForm.value[key] = data[key].defaultValue;
		});
};

watch(
	() => props.hyFormFields,
	(newVal) => {
		init(newVal);
	},
	{ immediate: true, deep: true }
);

const setRemove = (item: Iitem, type: string) => {
	if (item.type === type && item?.remove !== true) return true;
	return false;
};
const setRule = (item: Iitem, desc: string) => {
	if (hyFormConfig.value.type === 'view') return [];
	if (hyFormConfig.value.type === 'search') {
		if (item.rules && item.rules.length > 0) {
			return [
				...item.rules,
				{
					required: false,
				},
			];
		}
		return {
			required: false,
		};
	}
	if (hyFormConfig.value.type === 'submit') {
		//只有必输条件 eg:年龄必输
		if (item.required && !item.rules) {
			return [
				{
					required: item.required,
					message: `请${desc}${item.label || '此项内容'}`,
					trigger: ['change', 'blur'],
				},
			];
		}
		//必输，并且有其他条件 eg:年龄必输，并且要超过18岁
		if (item.required && item.rules && item.rules.length > 0) {
			return [
				...item.rules,
				{
					required: item.required,
					message: `请${desc}${item.label || '此项内容'}`,
					trigger: ['change', 'blur'],
				},
			];
		}
		//非必输，有其他条件 eg:年龄非必输，超过18岁
		if (item.rules && item.rules.length > 0) {
			return [
				...item.rules,
				{
					required: item.required,
					message: `请${desc}${item.label || '此项内容'}`,
					trigger: ['change', 'blur'],
				},
			];
		}
	}
};
const setLabelWidth = (item: Iitem) => {
	return item?.labelWidth || hyFormConfig.value.labelWidth;
};
const setDisabled = (item: Iitem) => {
	if (hyFormConfig.value.type === 'view') return true;
	else return item.disabled || false;
};
const setPlaceholder = (item: Iitem, desc: string) => {
	if (item.placeholder) return item.placeholder;
	if (hyFormConfig.value.type !== 'view') {
		return `请${desc}${item.label}`;
	}
	return '';
};
const setFocus = (item: Iitem, e: Event) => {
	if (item.focus) return item.focus(e);
	return null;
};
const setBlur = (item: Iitem, e: Event) => {
	if (item.blur) return item.blur(e);
	return null;
};
const setClick = (item: Iitem, e: Event) => {
	if (item.click) return item.click(e);
	return null;
};
const setChange = (item: Iitem, e: Event) => {
	if (item.change) return item.change(e);
	return null;
};
// ref提升,hyFormRef方法暴露到实力上。
const hyFormRef = ref<any>(null);
const refUp = () => {
	const instance: any = getCurrentInstance();
	const entries = Object.entries(hyFormRef.value.$.exposed);
	for (const [key, value] of entries) {
		instance.exposed[key] = value;
	}
};
onMounted(() => {
	refUp();
});
//表单校验
const check = async () => {
	return hyFormRef.value.validate((valid: boolean) => {
		if (!valid) {
			setTimeout(() => {
				const el = document.querySelectorAll('.el-form-item__error')[0];
				el.scrollIntoView({ block: 'center', behavior: 'smooth' });
			}, 100);
			if (props.hyFormConfig.showErrorMessage) ElMessage.error('表单中有必填项未填写，请检查并补全');
		}
		return valid;
	});
};
//表单提交
const submit = () => {
	let submitData: any = {};
	for (const key in hyForm.value) {
		submitData[key] = hyForm.value[key];
		// 空值处理
		if (hyForm.value[key] === null || hyForm.value[key] === undefined) {
			submitData[key] = '';
		}
		//数字处理
		if (Array.isArray(hyForm.value[key])) {
			submitData[key] = hyForm.value[key].join(',');
		}
	}
	return submitData;
};
//下拉菜单传递参数判断逻辑
const emit = defineEmits(['clickDropdown']);
const clickDropdown = (value?: any) => {
	emit('clickDropdown', value);
};

defineExpose({ hyForm, check, submit });
</script>
<style scoped lang="scss">
.buildForm {
	width: 100%;
	display: flex;
	flex-wrap: wrap;
	.item {
		width: 500px;
		margin-bottom: 25px;
	}
	.item-single {
		@extend .item;
		width: 100%;
	}
}
</style>
